import React, { memo, useCallback, useEffect, useState } from 'react';
import { useRef } from 'react';
import { useMemo } from 'react';
import { Animated, ScrollView, View } from 'react-native';
import {
  setPages,
  setAnimated,
  scrollSetting,
  SwiperProps,
  setCardSetting,
  Context,
  getAutoPlayPageIndex,
  getDragPageIndex,
} from './_swiper';
import { Style } from './swiper.style';
import { Indicator } from './indicator';

export const SwiperR: React.FC<SwiperProps> = memo(
  ({
    children,
    style,
    autoPlay = false,
    cardSetting = { cardSmallSide: 0, cardSpace: 0 },
    interval = 2000,
    isShowIndicator = true,
    mode = 'normal',
  }) => {
    let currentPageFloat = 2;
    let scrollIndex = useRef(2);
    let currentContentOffset = 0;
    let containerRef = useRef<View>();
    const isAutoPlay = autoPlay;
    const timerSign = useRef<NodeJS.Timeout>();
    const scrollViewRef = useRef<ScrollView>(null);
    const Pages = React.Children.toArray(children);
    const [containerWidthState, setContainerWidthState] = useState(0);
    const [containerHeightState, setContainerHeightState] = useState(0);

    // set the header and foorter page
    setPages(Pages);
    const translateAnimList = useRef(
      React.Children.map(Pages, () => new Animated.Value(0)),
    ).current;
    const scaleAnimList = useRef(
      React.Children.map(Pages, () => new Animated.Value(1)),
    ).current;
    const pageTotal = Pages.length;

    const iorOpacityAnimatedList = useRef(
      new Array(pageTotal - 4).fill(undefined).map((_, index) => {
        if (index === 0) {
          return new Animated.Value(1);
        }
        return new Animated.Value(0);
      }),
    );
    const scaleRate = useMemo(() => {
      return cardSetting.cardSpace / (containerHeightState || 2);
    }, [cardSetting.cardSpace, containerHeightState]);
    setCardSetting(mode, cardSetting);
    const setInitialContentOffset = useCallback(() => {
      scrollViewRef.current.scrollTo({
        y: 0,
        x: containerWidthState * 2,
        animated: false,
      });
    }, [containerWidthState]);
    const getCardWidth = useCallback(() => {
      if (mode === 'normal') {
        return containerWidthState;
      } else if (mode === 'cardSide') {
        return cardSetting.cardSide || containerWidthState;
      }
    }, [cardSetting.cardSide, containerWidthState, mode]);

    const whiteSpace = useMemo(() => {
      return (containerWidthState - getCardWidth()) / 2;
    }, [getCardWidth, containerWidthState]);
    if (mode === 'cardSide') {
      setAnimated(
        translateAnimList,
        scaleAnimList,
        scrollIndex.current,
        currentPageFloat,
        whiteSpace,
        scaleRate,
        cardSetting,
      );
    }
    const previewChildren = useMemo(() => {
      return Pages.map((child, index) => {
        return (
          <Animated.View
            key={index}
            style={[
              Style.childContainerStyle,
              {
                transform: [
                  {
                    translateX: translateAnimList[index],
                  },
                  {
                    scale: scaleAnimList[index],
                  },
                ],
              },
              {
                width: containerWidthState,
              },
            ]}>
            <View style={[Style.cardStyle, { width: whiteSpace }]} />
            {child}
            <View style={[Style.cardStyle, { width: whiteSpace }]} />
          </Animated.View>
        );
      });
    }, [
      Pages,
      containerWidthState,
      scaleAnimList,
      translateAnimList,
      whiteSpace,
    ]);

    const isStartOrEnd = useCallback(() => {
      let flag = false;
      if (scrollIndex.current >= pageTotal - 2) {
        scrollViewRef.current?.scrollTo({
          y: 0,
          x: 2 * containerWidthState,
          animated: false,
        });
        flag = true;
      } else if (scrollIndex.current <= 1) {
        scrollViewRef.current?.scrollTo({
          y: 0,
          x: (pageTotal - 3) * containerWidthState,
          animated: false,
        });
        flag = true;
      }
      return flag;
    }, [containerWidthState, pageTotal]);

    const startAutoPlay = useCallback(() => {
      if (timerSign.current) {
        clearInterval(timerSign.current);
      }
      if (!isAutoPlay) {
        return;
      }
      timerSign.current = setInterval(() => {
        if (isStartOrEnd()) {
          scrollIndex.current = 2;
        }
        scrollViewRef.current?.scrollTo({
          y: 0,
          x: (scrollIndex.current + 1) * containerWidthState,
        });

        iorOpacityAnimatedList.current.forEach((_, index) => {
          _.setValue(0);
          if (index === getAutoPlayPageIndex(pageTotal, scrollIndex.current)) {
            _.setValue(1);
          }
        });
      }, interval);
    }, [containerWidthState, interval, isAutoPlay, isStartOrEnd, pageTotal]);

    useEffect(() => {
      setInitialContentOffset();
      if (isAutoPlay) {
        startAutoPlay();
      }
      return () => {
        clearInterval(timerSign.current);
      };
    }, [startAutoPlay, isAutoPlay, setInitialContentOffset]);

    return (
      <Context.Provider
        value={{
          pageTotal,
          opacityAminatedList: iorOpacityAnimatedList.current,
        }}>
        <View ref={containerRef} style={style}>
          <ScrollView
            onLayout={e => {
              setContainerWidthState(e.nativeEvent.layout.width);
              setContainerHeightState(e.nativeEvent.layout.height);
            }}
            horizontal
            pagingEnabled
            ref={scrollViewRef}
            contentContainerStyle={[Style.contentContainerStyle]}
            showsHorizontalScrollIndicator={false}
            showsVerticalScrollIndicator={false}
            scrollEventThrottle={3}
            contentOffset={{
              x: containerWidthState * scrollIndex.current,
              y: 0,
            }}
            onScrollBeginDrag={() => {
              if (timerSign.current) {
                clearInterval(timerSign.current);
              }
            }}
            onScrollEndDrag={() => {
              if (isAutoPlay) {
                startAutoPlay();
              }
            }}
            onMomentumScrollEnd={() => {
              isStartOrEnd();
              iorOpacityAnimatedList.current.forEach((_, index) => {
                _.setValue(0);
                if (
                  index === getDragPageIndex(pageTotal, scrollIndex.current)
                ) {
                  _.setValue(1);
                }
              });
            }}
            onScroll={e => {
              ({
                contentOffset: currentContentOffset,
                currentPageFloat,
                scrollIndex,
              } = scrollSetting(
                currentContentOffset,
                e,
                currentPageFloat,
                scrollIndex,
                containerWidthState,
              ));

              setAnimated(
                translateAnimList,
                scaleAnimList,
                scrollIndex.current,
                currentPageFloat,
                whiteSpace,
                scaleRate,
                cardSetting,
              );
            }}>
            {previewChildren}
          </ScrollView>
          {(() => {
            return isShowIndicator ? <Indicator /> : null;
          })()}
        </View>
      </Context.Provider>
    );
  },
);
